import com.google.common.io.Files;
import com.google.common.io.InputSupplier;
import data.JSONDataInserter;
import play.Application;
import play.GlobalSettings;
import play.Logger;
import play.Play;
import play.db.jpa.JPA;
import play.libs.F.Function0;

import at.ac.tuwien.big.we14.lab4.dbpedia.api.*;
import at.ac.tuwien.big.we14.lab4.dbpedia.vocabulary.*;
import com.hp.hpl.jena.vocabulary.*;
import com.hp.hpl.jena.sparql.vocabulary.FOAF;
import com.hp.hpl.jena.rdf.model.*;
import java.util.Locale;
import java.util.List;
import java.util.Iterator;
import java.math.BigDecimal;
import java.util.Collections;
import java.util.GregorianCalendar;

import models.*;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

public class Global extends GlobalSettings {
	
	@play.db.jpa.Transactional
	public static void insertJSonData() throws IOException {
		File file = new File(Play.application().configuration().getString("questions.filePath"));
		InputSupplier<FileInputStream> inputStreamSupplier = 
				Files.newInputStreamSupplier(file);
		FileInputStream inputStream = inputStreamSupplier.getInput();
		JSONDataInserter.insertData(inputStream);
		Logger.info("Data from json file '" + file.getName() + "' inserted.");
	}


	@play.db.jpa.Transactional
	public static void insertDBpedia() {
		if(!DBPediaService.isAvailable()) {
			Logger.info("DBpedia is currently not available.");
			return;
		}
		
		Category category;
		Model games;
		List<String> germanGames;
		List<String> englishGames;
		Iterator germanIt;
		Iterator englishIt;
		Choice choice;
		SelectQueryBuilder gameQuery;
		Question question;

		Resource rpgGames = DBPediaService.loadStatements(DBPedia.createResource("Role-playing_video_game"));

		/*
		 * Question if games are from square enix
		 */
		Resource developer = DBPediaService.loadStatements(DBPedia.createResource("Square_Enix"));

		String germanDeveloperName = DBPediaService.getResourceName(developer, Locale.GERMAN.toString());
		String englishDeveloperName = DBPediaService.getResourceName(developer, Locale.GERMAN.toString());

		category = new Category();

		category.setName(DBPediaService.getResourceName(rpgGames, Locale.GERMAN), Locale.GERMAN.toString());
		category.setName(DBPediaService.getResourceName(rpgGames, Locale.ENGLISH), Locale.ENGLISH.toString());

		question = new Question();
		question.setText("Welche der folgenden Rollenspiele wurde nicht von " + germanDeveloperName + " entwickelt?", Locale.GERMAN.toString());
		question.setText("Which of the following rpg games was not developed by " + englishDeveloperName + "?", Locale.ENGLISH.toString());

		gameQuery = DBPediaService.createQueryBuilder()
			.setOffset(3)
			.setLimit(4)
			.addWhereClause(DBPediaOWL.genre, rpgGames)
			.addWhereClause(DBPediaOWL.developer, developer)
			.addFilterClause(RDFS.label, Locale.GERMAN)
			.addFilterClause(RDFS.label, Locale.ENGLISH);

		games = DBPediaService.loadStatements(gameQuery.toQueryString());
		germanGames = DBPediaService.getResourceNames(games, Locale.GERMAN);
		englishGames = DBPediaService.getResourceNames(games, Locale.ENGLISH);

		germanIt = germanGames.iterator();
		englishIt = englishGames.iterator();
		while (germanIt.hasNext() && englishIt.hasNext()) { 
			choice = new Choice();
			choice.setText(germanIt.next().toString(), Locale.GERMAN.toString());
			choice.setText(englishIt.next().toString(), Locale.ENGLISH.toString());
			question.addWrongChoice(choice);
		}

		gameQuery.removeWhereClause(DBPediaOWL.developer, developer);
		gameQuery.addMinusClause(DBPediaOWL.developer, developer);
		gameQuery.setOffset(50);

		games = DBPediaService.loadStatements(gameQuery.toQueryString());
		germanGames = DBPediaService.getResourceNames(games, Locale.GERMAN);
		englishGames = DBPediaService.getResourceNames(games, Locale.ENGLISH);

		germanIt = germanGames.iterator();
		englishIt = englishGames.iterator();
		while (germanIt.hasNext() && englishIt.hasNext()) { 
			choice = new Choice();
			choice.setText(germanIt.next().toString(), Locale.GERMAN.toString());
			choice.setText(englishIt.next().toString(), Locale.ENGLISH.toString());
			question.addRightChoice(choice);
		}

		question.setMaxTime(new BigDecimal(30));
		
		Collections.shuffle(question.getChoices());

		category.addQuestion(question);

		/*
		 * Question if game is on Super Nintendo
		 */
		Resource computingPLatform = DBPediaService.loadStatements(DBPedia.createResource("Super_Nintendo_Entertainment_System"));

		String germanComputingPLatform = DBPediaService.getResourceName(computingPLatform, Locale.GERMAN.toString());
		String englishComputingPLatform = DBPediaService.getResourceName(computingPLatform, Locale.ENGLISH.toString());

		question = new Question();
		question.setText("Welche der folgenden Rollenspiele sind für das " + germanComputingPLatform + " erhältlich?", Locale.GERMAN.toString());
		question.setText("Which of the following rpg games are available for the " + englishComputingPLatform + "?", Locale.ENGLISH.toString());

		gameQuery = DBPediaService.createQueryBuilder()
			.setOffset(7)
			.setLimit(2)
			.addWhereClause(DBPediaOWL.genre, rpgGames)
			.addWhereClause(DBPediaOWL.computingPlatform, computingPLatform)
			.addFilterClause(RDFS.label, Locale.GERMAN)
			.addFilterClause(RDFS.label, Locale.ENGLISH);

		games = DBPediaService.loadStatements(gameQuery.toQueryString());
		germanGames = DBPediaService.getResourceNames(games, Locale.GERMAN);
		englishGames = DBPediaService.getResourceNames(games, Locale.ENGLISH);

		germanIt = germanGames.iterator();
		englishIt = englishGames.iterator();
		while (germanIt.hasNext() && englishIt.hasNext()) { 
			choice = new Choice();
			choice.setText(germanIt.next().toString(), Locale.GERMAN.toString());
			choice.setText(englishIt.next().toString(), Locale.ENGLISH.toString());
			question.addRightChoice(choice);
		}

		gameQuery.setLimit(3);
		gameQuery.removeWhereClause(DBPediaOWL.computingPlatform, computingPLatform);
		gameQuery.addMinusClause(DBPediaOWL.computingPlatform, computingPLatform);

		games = DBPediaService.loadStatements(gameQuery.toQueryString());
		germanGames = DBPediaService.getResourceNames(games, Locale.GERMAN);
		englishGames = DBPediaService.getResourceNames(games, Locale.ENGLISH);

		germanIt = germanGames.iterator();
		englishIt = englishGames.iterator();
		while (germanIt.hasNext() && englishIt.hasNext()) { 
			choice = new Choice();
			choice.setText(germanIt.next().toString(), Locale.GERMAN.toString());
			choice.setText(englishIt.next().toString(), Locale.ENGLISH.toString());
			question.addWrongChoice(choice);
		}

		question.setMaxTime(new BigDecimal(40));
		
		Collections.shuffle(question.getChoices());

		category.addQuestion(question);
		
		/*
		 * Question if game is released before 2000
		 */
		question = new Question();
		question.setText("Welche der folgenden Rollenspiele sind vor dem Jahr 2000 erschienen?", Locale.GERMAN.toString());
		question.setText("Which of the following rpg games where available before the year 2000?", Locale.ENGLISH.toString());

		gameQuery = DBPediaService.createQueryBuilder()
			.setOffset(6)
			.setLimit(4)
			.addWhereClause(DBPediaOWL.genre, rpgGames)
			.addFilterClause(DBPediaOWL.releaseDate, new GregorianCalendar(2000, 1, 1), SelectQueryBuilder.MatchOperation.LESS)
			.addFilterClause(RDFS.label, Locale.GERMAN)
			.addFilterClause(RDFS.label, Locale.ENGLISH);

		games = DBPediaService.loadStatements(gameQuery.toQueryString());
		germanGames = DBPediaService.getResourceNames(games, Locale.GERMAN);
		englishGames = DBPediaService.getResourceNames(games, Locale.ENGLISH);

		germanIt = germanGames.iterator();
		englishIt = englishGames.iterator();
		while (germanIt.hasNext() && englishIt.hasNext()) { 
			choice = new Choice();
			choice.setText(germanIt.next().toString(), Locale.GERMAN.toString());
			choice.setText(englishIt.next().toString(), Locale.ENGLISH.toString());
			question.addRightChoice(choice);
		}

		gameQuery = DBPediaService.createQueryBuilder()
			.setOffset(10)
			.setLimit(2)
			.addWhereClause(DBPediaOWL.genre, rpgGames)
			.addFilterClause(DBPediaOWL.releaseDate, new GregorianCalendar(2000, 1, 1), SelectQueryBuilder.MatchOperation.GREATER_OR_EQUAL)
			.addFilterClause(RDFS.label, Locale.GERMAN)
			.addFilterClause(RDFS.label, Locale.ENGLISH);

		games = DBPediaService.loadStatements(gameQuery.toQueryString());
		germanGames = DBPediaService.getResourceNames(games, Locale.GERMAN);
		englishGames = DBPediaService.getResourceNames(games, Locale.ENGLISH);

		germanIt = germanGames.iterator();
		englishIt = englishGames.iterator();
		while (germanIt.hasNext() && englishIt.hasNext()) { 
			choice = new Choice();
			choice.setText(germanIt.next().toString(), Locale.GERMAN.toString());
			choice.setText(englishIt.next().toString(), Locale.ENGLISH.toString());
			question.addWrongChoice(choice);
		}

		question.setMaxTime(new BigDecimal(35));
		
		Collections.shuffle(question.getChoices());

		category.addQuestion(question);

		/*
		 * Question if game is part of a series
		 */
		Resource series = DBPediaService.loadStatements(DBPedia.createResource("Chrono_(series)"));

		String germanSeries = DBPediaService.getResourceName(series, Locale.GERMAN.toString());
		String englishSeries = DBPediaService.getResourceName(series, Locale.ENGLISH.toString());
		if (germanSeries.equals("")) {
			germanSeries = englishSeries;
		}

		question = new Question();
		question.setText("Welche der folgenden Rollenspiele sind teil von " + germanSeries + "?", Locale.GERMAN.toString());
		question.setText("Which of the following rpg games are part of " + englishSeries + "?", Locale.ENGLISH.toString());

		gameQuery = DBPediaService.createQueryBuilder()
			.addWhereClause(DBPediaOWL.genre, rpgGames)
			.addWhereClause(DBPediaOWL.series, series)
			.addFilterClause(RDFS.label, Locale.GERMAN)
			.addFilterClause(RDFS.label, Locale.ENGLISH);

		games = DBPediaService.loadStatements(gameQuery.toQueryString());
		germanGames = DBPediaService.getResourceNames(games, Locale.GERMAN);
		englishGames = DBPediaService.getResourceNames(games, Locale.ENGLISH);

		germanIt = germanGames.iterator();
		englishIt = englishGames.iterator();
		while (germanIt.hasNext() && englishIt.hasNext()) { 
			choice = new Choice();
			choice.setText(germanIt.next().toString(), Locale.GERMAN.toString());
			choice.setText(englishIt.next().toString(), Locale.ENGLISH.toString());
			question.addRightChoice(choice);
		}

		gameQuery.setLimit(1);
		gameQuery.setOffset(20);
		gameQuery.removeWhereClause(DBPediaOWL.series, series);
		gameQuery.addMinusClause(DBPediaOWL.series, series);

		games = DBPediaService.loadStatements(gameQuery.toQueryString());
		germanGames = DBPediaService.getResourceNames(games, Locale.GERMAN);
		englishGames = DBPediaService.getResourceNames(games, Locale.ENGLISH);

		gameQuery.setOffset(50);

		games = DBPediaService.loadStatements(gameQuery.toQueryString());
		germanGames.addAll(DBPediaService.getResourceNames(games, Locale.GERMAN));
		englishGames.addAll(DBPediaService.getResourceNames(games, Locale.ENGLISH));

		gameQuery.setOffset(60);

		games = DBPediaService.loadStatements(gameQuery.toQueryString());
		germanGames.addAll(DBPediaService.getResourceNames(games, Locale.GERMAN));
		englishGames.addAll(DBPediaService.getResourceNames(games, Locale.ENGLISH));

		germanIt = germanGames.iterator();
		englishIt = englishGames.iterator();
		while (germanIt.hasNext() && englishIt.hasNext()) { 
			choice = new Choice();
			choice.setText(germanIt.next().toString(), Locale.GERMAN.toString());
			choice.setText(englishIt.next().toString(), Locale.ENGLISH.toString());
			question.addWrongChoice(choice);
		}

		question.setMaxTime(new BigDecimal(25));
		
		Collections.shuffle(question.getChoices());

		category.addQuestion(question);

		/*
		 * Question if game was designed and developed from the same person
		 */
		Resource designer = DBPediaService.loadStatements(DBPedia.createResource("Richard_Garriott"));

		String germanDesigner = DBPediaService.getResourceName(designer, Locale.GERMAN.toString());
		String englishDesigner = DBPediaService.getResourceName(designer, Locale.ENGLISH.toString());
		if (germanDesigner.equals("")) {
			germanDesigner = englishDesigner;
		}

		question = new Question();
		question.setText("Welche der folgenden Rollenspiele wurde von " + germanDesigner + " designt als auch enwickelt?", Locale.GERMAN.toString());
		question.setText("Which of the following rpg games was designed and developed by " + englishDesigner + "?", Locale.ENGLISH.toString());

		gameQuery = DBPediaService.createQueryBuilder()
			.addWhereClause(DBPediaOWL.genre, rpgGames)
			.addWhereClause(DBPediaOWL.designer, designer)
			.addWhereClause(DBPediaOWL.developer, designer)
			.addFilterClause(RDFS.label, Locale.ENGLISH);

		games = DBPediaService.loadStatements(gameQuery.toQueryString());
		germanGames = DBPediaService.getResourceNames(games, Locale.ENGLISH);
		englishGames = DBPediaService.getResourceNames(games, Locale.ENGLISH);

		germanIt = germanGames.iterator();
		englishIt = englishGames.iterator();
		while (germanIt.hasNext() && englishIt.hasNext()) { 
			choice = new Choice();
			choice.setText(germanIt.next().toString(), Locale.GERMAN.toString());
			choice.setText(englishIt.next().toString(), Locale.ENGLISH.toString());
			question.addRightChoice(choice);
		}

		gameQuery.removeWhereClause(DBPediaOWL.developer, designer);
		gameQuery.addMinusClause(DBPediaOWL.developer, designer);

		games = DBPediaService.loadStatements(gameQuery.toQueryString());
		germanGames = DBPediaService.getResourceNames(games, Locale.ENGLISH);
		englishGames = DBPediaService.getResourceNames(games, Locale.ENGLISH);

		germanIt = germanGames.iterator();
		englishIt = englishGames.iterator();
		while (germanIt.hasNext() && englishIt.hasNext()) { 
			choice = new Choice();
			choice.setText(germanIt.next().toString(), Locale.GERMAN.toString());
			choice.setText(englishIt.next().toString(), Locale.ENGLISH.toString());
			question.addWrongChoice(choice);
		}

		question.setMaxTime(new BigDecimal(55));
		
		Collections.shuffle(question.getChoices());

		category.addQuestion(question);
		/*
		 * Save category
		 */
		QuizDAO.INSTANCE.persist(category);

	}
	
	@play.db.jpa.Transactional
    public void onStart(Application app) {
       try {
		JPA.withTransaction(new Function0<Boolean>() {

			@Override
			public Boolean apply() throws Throwable {
				insertJSonData();
				insertDBpedia();
				return true;
			}
			   
			});
	} catch (Throwable e) {
		e.printStackTrace();
	}
       
    }

    public void onStop(Application app) {
        Logger.info("Application shutdown...");
    }

}
